package com.bjb.vr.common.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * @description: 通用时间操作工具类
 * @author: HuJingBo
 * @time: 2022/2/16 20:18
 */
public class DateTimeUtil {

    private static final ZoneId DEFAULT_ZONE = ZoneId.systemDefault();

    public static final String DATE_FORMAT_MINITE = "yyyy-MM-dd HH:mm";
    public static final String DATE_FORMAT_DAY = "yyyy-MM-dd";
    public static final String DATE_FORMAT_SECOND = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_SECOND_12 = "yyyy-MM-dd hh:mm:ss";
    public static final String DATE_FORMAT_MILLISECOND = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_FORMAT_CHINESE = "yyyy年MM月dd日";
    public static final String DATE_FORMAT_CHINESE_SECONDE = "yyyy年MM月dd日 HH:mm:ss";
    public static final String DATE_FORMAT_CHINESE_WEEK_SECONDE = "yyyy年MM月dd日 E HH:mm:ss";
    public static final String YYYYMMDD = "yyyyMMdd";
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
    private final static String[] WEEK_ARR = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};


    private DateTimeUtil() {
        throw new UnsupportedOperationException("You can't instantiate me ......");
    }

    /**
     * 获取LocalDate
     *
     * @param dateStr
     * @return
     */
    public static LocalDate getLocalDate(String dateStr) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
    }

    /**
     * 获取LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate getLocalDate(Date date) {
        return getLocalDateTime(date).toLocalDate();
    }

    /**
     * 获取LocalDateTime
     *
     * @param date
     * @return
     */
    public static LocalDateTime getLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), DEFAULT_ZONE);
    }

    /**
     * 获取当前时间戳
     *
     * @return
     */
    public static long nowTimeStamp() {
        return System.currentTimeMillis();
    }

    /**
     * 获取当前时间字符串
     *
     * @return
     */
    public static String nowStrTime() {
        return LocalDateTime.now().atZone(DEFAULT_ZONE).format(DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
    }

    /**
     * 获取当前时间字符串(自定义格式)
     *
     * @param format
     * @return
     */
    public static String nowStrTime(String format) {
        return LocalDateTime.now().atZone(DEFAULT_ZONE).format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 获取标准日期时间(yyyy-MM-dd HH:mm:ss)
     *
     * @param date
     * @return
     */
    public static String getStandardDateTimeString(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
    }

    /**
     * 获取标准日期(yyyy-MM-dd)
     *
     * @param date
     * @return
     */
    public static String getStandardDateString(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT_DAY));
    }

    /**
     * 获取默认日期(yyyyMMdd)
     *
     * @param date
     * @return
     */
    public static String getDefaultDateString(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(YYYYMMDD));
    }

    /**
     * localDateTime to date
     *
     * @param localDateTime
     * @return
     */
    public static Date getDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取两个时间天数之差
     *
     * @param dateTime1
     * @param dateTime2
     * @return
     */
    public static int betweenDays(String dateTime1, String dateTime2) {
        return Period.between(getLocalDate(dateTime1), getLocalDate(dateTime2)).getDays();
    }

    /**
     * 获取两个时间天数之差
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int betweenDays(LocalDate date1, LocalDate date2) {
        return Period.between(date1, date2).getDays();
    }

    /**
     * 获取昨天(String类型) 2022-02-20
     *
     * @return
     */
    public static String getYesterday() {
        LocalDate localDate = LocalDate.now().minusDays(1);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return getStandardDateString(date);
    }

    /**
     * 获取昨天(String类型) 20220220
     *
     * @return
     */
    public static String getYesterdayStander() {
        LocalDate localDate = LocalDate.now().minusDays(1);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return getDefaultDateString(date);
    }

    /**
     * 获取昨天(Date类型) Sun Feb 20 00:00:00 CST 2022
     *
     * @return
     */
    public static Date getYesterdayStanderDate() {
        LocalDate localDate = LocalDate.now().minusDays(1);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return date;
    }

    /**
     * 获取LocalDateTime
     *
     * @param instant
     * @return
     */
    public static LocalDateTime getLocalDateTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
    }

    /**
     * 获取指定日期与当前日期秒数之差
     *
     * @param date
     * @return
     */
    public static long betweenNowSecond(Date date) {
        LocalDateTime start = DateTimeUtil.getLocalDateTime(date.toInstant());
        return ChronoUnit.SECONDS.between(start, LocalDateTime.now());
    }

    /**
     * 获取指定日期与当前日期分钟数之差
     *
     * @param date
     * @return
     */
    public static long betweenNowMinute(Date date) {
        LocalDateTime start = DateTimeUtil.getLocalDateTime(date.toInstant());
        return ChronoUnit.MINUTES.between(start, LocalDateTime.now());
    }

    /**
     * 获取指定日期与当前日期天数之差
     *
     * @param date
     * @return
     */
    public static long betweenNowDay(Date date) {
        LocalDateTime start = DateTimeUtil.getLocalDateTime(date.toInstant());
        return ChronoUnit.DAYS.between(start, LocalDateTime.now());
    }

    /**
     * 获取两个时间月数之差
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long betweenMonths(Date startDate, Date endDate) {
        LocalDateTime startTime = DateTimeUtil.getLocalDateTime(startDate.toInstant());
        LocalDateTime endTime = DateTimeUtil.getLocalDateTime(endDate.toInstant());
        return ChronoUnit.MONTHS.between(startTime, endTime);
    }

    /**
     * 获取两个时间年数之差
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long betweenYears(Date startDate, Date endDate) {
        LocalDateTime startTime = DateTimeUtil.getLocalDateTime(startDate.toInstant());
        LocalDateTime endTime = DateTimeUtil.getLocalDateTime(endDate.toInstant());
        return ChronoUnit.YEARS.between(startTime, endTime);
    }

    /**
     * 获取现在的时间(Date类型)
     *
     * @return
     */
    public static Date getNowTime() {
        LocalDateTime localDateTime = LocalDateTime.now();
        return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取当天日期
     *
     * @return
     */
    public static Date getNowDate() {
        LocalDate localDate = LocalDate.now();
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于指定时间指定天数的日期
     *
     * @param date
     * @param minusDays
     * @return
     */
    public static Date getBeforeDate(Date date, long minusDays) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate1 = localDate.minusDays(minusDays);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于当前时间指定小时的时间
     *
     * @param minusHours
     * @return
     */
    public static String getBeforeHours(long minusHours) {
        LocalDateTime localDateTime = LocalDateTime.now().minusHours(minusHours);
        return localDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
    }

    /**
     * 获取早于当前时间指定月数的日期
     *
     * @param minusMonths
     * @return
     */
    public static Date getBeforeMonth(long minusMonths) {
        LocalDate localDate = LocalDate.now().minusMonths(minusMonths);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于当前时间指定分钟的时间
     *
     * @param minusMinutes
     * @return
     */
    public static String getBeforeMinute(long minusMinutes) {
        LocalDateTime localDateTime = LocalDateTime.now().minusMinutes(minusMinutes);
        return localDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
    }

    /**
     * 获取早于指定时间指定分钟的时间
     *
     * @param minusMinutes
     * @return
     */
    public static Date getBeforeMinuteByStartTime(long minusMinutes, Date startTime) {
        LocalDateTime localDateTime = getLocalDateTime(startTime).minusMinutes(minusMinutes);
        ZonedDateTime zonedDateTime = localDateTime.atZone(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于当前时间指定天数的日期
     *
     * @param minusDays
     * @return
     */
    public static Date getBeforeDate(long minusDays) {
        LocalDate localDate = LocalDate.now().minusDays(minusDays);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于指定时间指定天数的日期
     *
     * @param minusDays
     * @param date
     * @return
     */
    public static Date getBeforeDate(long minusDays, Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        LocalDate localDate = localDateTime.toLocalDate();
        LocalDate localDate1 = localDate.minusDays(minusDays);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取晚于当前时间指定分钟的时间
     *
     * @param plusMinutes
     * @return
     */
    public static Date getNextMinute(long plusMinutes) {
        LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(plusMinutes);
        return getDate(localDateTime);
    }


    /**
     * 获取早于当前时间指定秒的时间
     *
     * @param minusSeconds
     * @return
     */
    public static LocalDateTime getBeforeSecond(long minusSeconds) {
        LocalDateTime localDateTime = LocalDateTime.now().minusSeconds(minusSeconds);
        return localDateTime;
    }

    /**
     * 获取晚于当前时间指定秒的时间
     *
     * @param plusSeconds
     * @return
     */
    public static LocalDateTime getNextSecond(long plusSeconds) {
        LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(plusSeconds);
        return localDateTime;
    }

    /**
     * 获取晚于当前时间指定天数的日期
     *
     * @param plusDays
     * @return
     */
    public static Date getNextDate(long plusDays) {
        LocalDate localDate = LocalDate.now().plusDays(plusDays);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取当天开始时间
     *
     * @param dateStr
     * @return
     */
    public static Date getTodayStartTime(String dateStr) {
        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN);
        return getDate(localDateTime);
    }

    /**
     * 获取当天结束时间
     *
     * @param dateStr
     * @return
     */
    public static Date getTodayLastTime(String dateStr) {
        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MAX);
        return getDate(localDateTime);
    }

    /**
     * 获取当前时间下一年
     *
     * @param date
     * @return
     */
    public static Date getNextYear(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate1 = localDate.plusYears(1);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取当前时间下一个月
     *
     * @param date
     * @return
     */
    public static Date getNextMonth(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate1 = localDate.plusMonths(1);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * localDate to date
     *
     * @param localDate
     * @return
     */
    public static Date localDate2Date(LocalDate localDate) {
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取当前时间年份
     *
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        return getLocalDateTime(date).getYear();
    }

    /**
     * 获取当前时间月份
     *
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        return getLocalDateTime(date).getMonth().getValue();
    }

    /**
     * 获取当前时间年份、月份
     *
     * @param date
     * @return
     */
    public static String getYearAndMonth(Date date) {
        int year = getLocalDateTime(date).getYear();
        int month = getLocalDateTime(date).getMonth().getValue();
        String monthSuffix = String.format("%02d", month);
        return year + monthSuffix;
    }

    /**
     * timestamp to String
     *
     * @param timestamp
     * @return
     */
    public static String timeStampToDateStr(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
        return localDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT_SECOND));
    }

    /**
     * timestamp to date
     *
     * @param timestamp
     * @return
     */
    public static Date timeStampToDate(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, DEFAULT_ZONE);
        return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 获取本周第一天
     */
    public static String firstDayOfWeek() {
        LocalDate now = LocalDate.now();
        LocalDate localDate = now.with(DayOfWeek.MONDAY);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return getStandardDateString(date);
    }

    /**
     * 获取本周最后一天
     */
    public static String lastDayOfWeek() {
        LocalDate now = LocalDate.now();
        LocalDate localDate = now.with(DayOfWeek.SUNDAY);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return getStandardDateString(date);
    }

    /**
     * 获取本月第一天
     */
    public static String firstDayOfMonth() {
        LocalDateTime thisMonthStart = LocalDateTime.of(LocalDate.from(LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth())), LocalTime.MIN);
        ZonedDateTime zonedDateTime = thisMonthStart.toLocalDate().atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return getStandardDateString(date);
    }

    /**
     * 获取本月最后一天
     */
    public static String lastDayOfMonth() {
        LocalDateTime thisMonthEnd = LocalDateTime.of(LocalDate.from(LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth())), LocalTime.MAX);
        ZonedDateTime zonedDateTime = thisMonthEnd.toLocalDate().atStartOfDay(DEFAULT_ZONE);
        Date date = Date.from(zonedDateTime.toInstant());
        return getStandardDateString(date);
    }

    /**
     * 获取传入天数的开始时间,如果为零则是当天，1为昨天
     */
    public static String getStartTime(int dayNum) {
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime minus = localDateTime.minus(Period.ofDays(dayNum));
        String startTime = minus.format(DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00"));
        return startTime;
    }

    /**
     * 获取传入天数的结束时间,如果为零则是当天，1为昨天
     */
    public static String getEndTime(int dayNum) {
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime minus = localDateTime.minus(Period.ofDays(dayNum));
        String endTime = minus.format(DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59"));
        return endTime;
    }
}
